package compilers.condition;

import java.io.BufferedWriter;
import java.io.IOException;

import compilers.stmt.Condition;
import compilers.table.MemScope;
import compilers.types.Type;

public class Term extends Condition {

	Term fChild1;
	Term fChild2;
	String fOp;
	
	public Term() {}
	
	public Term(Term fChild1, Term fChild2, String fOp) {
		super();
		this.fChild1 = fChild1;
		this.fChild2 = fChild2;
		this.fOp = fOp;
	}

	public void print(int tab) {
		for (int i=1;i<=tab;i++){System.out.print("\t");}System.out.print("|-");
		System.out.println("Term (" + fOp + ")");
		fChild1.print(tab+1);
		fChild2.print(tab+1);
	}
	
	public Type compute() {
		Type type1 = null;
		Type type2 = null;
		Type returnType = null;
		if (fChild1 instanceof Type) {
			type1 = (Type)fChild1;
		} else {
			type1 = fChild1.compute();
		}
		if (fChild2 instanceof Type) {
			type2 = (Type)fChild2;
		} else {
			type2 = fChild2.compute();
		}
		if ((type1 != null) && (type2 != null)) {
			if (((type1.isfValueSet()) || (type1.getfIdentifier() == null)) && ((type2.isfValueSet()) || (type2.getfIdentifier() == null))) {
				if (type1.isConstant() && type2.isConstant()) {
					if (type1.getClass().isInstance(type2)) {
						returnType = type1.computeOperation(type2, fOp);
					} else {
						returnType = type2.computeOperation(type1, fOp);
					}	
					return returnType;
				}
			}
		}
		return null;
	}
	
	public Type getBiggestType() {
		Type type1 = fChild1.getBiggestType();
		if(fChild2 == null) {
			return type1;
		}
		Type type2 = fChild2.getBiggestType();
		if(type2!=null && type2.getClass().isInstance(type1)) {
			return type2;
		}
		return type1;
	}

	@Override
	public void generate(BufferedWriter writer, MemScope scope) throws IOException {
		if (this.getfRes() == null) {
			System.out.println("TERM RES IS NULL");
			//System.err.println("Warning: no type, guessing type");
			this.setfRes((Type)fChild1);
			if(fChild2.getClass().isInstance(fChild1)) {
				this.setfRes((Type)fChild2);
			}
		} 
		
		Type calcType = getBiggestType();
		fChild1.setRes(calcType);
		fChild2.setRes(calcType);

		fChild1.generate(writer, scope);
		fChild2.generate(writer, scope);
		
		boolean convert = false;
				
		if (fOp.compareTo("+") == 0) {
			writer.write("add ");
			writer.write(calcType.getPType() + "\n");
			convert = true;
		} else if (fOp.compareTo("*") == 0) {
			writer.write("mul ");
			writer.write(calcType.getPType() + "\n");
			convert = true;
		} else if (fOp.compareTo("-") == 0) {
			writer.write("sub ");
			writer.write(calcType.getPType() + "\n");
			convert = true;
		} else if (fOp.compareTo("/") == 0) {
			writer.write("div ");
			writer.write(calcType.getPType() + "\n");
			convert = true;
		} else if (fOp.compareTo("==") == 0) {
			writer.write("equ ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo("!=") == 0) {
			writer.write("neq ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo("<") == 0) {
			writer.write("les ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo(">") == 0) {
			writer.write("grt ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo(">=") == 0) {
			writer.write("geq ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo("<=") == 0) {
			writer.write("leq ");
			writer.write(calcType.getPType() + "\n");
		} else if (fOp.compareTo("||") == 0) {
			writer.write("or\n");
		} else if (fOp.compareTo("&&") == 0) {
			writer.write("and\n");
		} else if (fOp.compareTo("%") == 0) {
			//int c = a - a / b * b;
			writer.write("div ");
			writer.write(calcType.getPType() + "\n");
			fChild2.generate(writer, scope);
			writer.write("mul ");
			writer.write(calcType.getPType() + "\n");
			fChild1.generate(writer, scope);
			writer.write("sub ");
			writer.write(calcType.getPType() + "\n");
			writer.write("neg ");
			writer.write(calcType.getPType() + "\n");
		} 
		
		if(calcType.getClass() != getfRes().getClass() && convert) {
			writer.write("conv " + calcType.getPType() + " " + this.getfRes().getPType() + "\n");
		}
	}

}
